package com.atguigu.gmall.payment.controller;

import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.model.enums.PaymentType;
import com.atguigu.gmall.model.payment.PaymentInfo;
import com.atguigu.gmall.payment.config.AlipayConfig;
import com.atguigu.gmall.payment.service.AlipayService;
import com.atguigu.gmall.payment.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;


/**
 * ClassName: AlipayApiController
 * Package: com.atguigu.gmall.payment.controller
 * Description:
 *
 * @Author 刘轩
 * @Create 2023-09-05 21:14
 * @Version 1.0
 */
@Slf4j
@RestController
@RequestMapping("/api/payment/alipay")
public class AlipayApiController {

    @Value("${app_id}")
    private String app_id;

    @Autowired
    private AlipayService alipayService;

    @Autowired
    private PaymentService paymentService;

    @Autowired
    private RedisTemplate redisTemplate;


    /**
     * 生成支付二维码
     *
     * @param orderId
     * @return
     */
    @GetMapping("/submit/{orderId}")
    public String submitOrder(@PathVariable Long orderId) {
        //  调用服务层方法
        String form = alipayService.createAlipay(orderId);
        //  返回表单
        return form;
    }

    /**
     * 同步回调 本质就是页面跳转 需要从service-payment 调整到 gmall-web/web-all
     */
    @GetMapping("/callback/return")
    public void callbackReturn(HttpServletResponse response, @RequestParam HashMap<String, Object> map) {
        System.out.println("map:" + map);
        //  重定向  http://payment.gmall.com/pay/success.html
        try {
            response.sendRedirect(AlipayConfig.return_order_url);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    // 异步通知
    @PostMapping("/callback/notify")
    public String callbackNotify(@RequestParam HashMap<String, String> paramsMap) {
        //Map<String, String> paramsMap = ... //将异步通知中收到的所有参数都存放到map中
        boolean signVerified = false; //调用SDK验证签名
        try {
            signVerified = AlipaySignature.rsaCheckV1(paramsMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }

        if (signVerified) {
            // TODO 验签成功后，按照支付结果异步通知中的描述，对支付结果中的业务内容进行二次校验，校验成功后在response中返回success并继续商户自身业务处理，校验失败返回failure
            // 第五步：需要严格按照如下描述校验通知数据的正确性：
            // 1. 商家需要验证该通知数据中的 out_trade_no 是否为商家系统中创建的订单号。
            // 2. 判断 total_amount 是否确实为该订单的实际金额（即商家订单创建时的金额）。
            // 3. 校验通知中的 seller_id（或者 seller_email) 是否为 out_trade_no 这笔单据的对应的操作方（有的时候，一个商家可能有多个 seller_id/seller_email）。
            // 4. 验证 app_id 是否为该商家本身
            try {
                String outTradeNo = paramsMap.get("out_trade_no");
                String totalAmount = paramsMap.get("total_amount");
                String appId = paramsMap.get("app_id");
                String notifyId = paramsMap.get("notify_id");
                // 获取交易状态
                String tradeStatus = paramsMap.get("trade_status");
                // 通过outTradeNo 查询paymentInfo 如果有记录 则说明out_trade_no 一样的！
                PaymentInfo paymentInfoQuery = paymentService.getPaymentInfo(outTradeNo, PaymentType.ALIPAY.name());
//  if(paymentInfoQuery.getTotalAmount().compareTo(new BigDecimal(totalAmount))!=0){
//      return "failure";
//  }
                if (paymentInfoQuery == null || new BigDecimal("0.01").compareTo(new BigDecimal(totalAmount)) != 0
                        || !app_id.equals(appId)) {
                    return "failure";
                }
                // 为了保证消息的幂等性 需要将notify_id 存储到redis
                Boolean reslut = redisTemplate.opsForValue().setIfAbsent(notifyId, notifyId, 24 * 60 + 24, TimeUnit.MINUTES);
                if (!reslut) {
                    return "failure";
                }
                // 判断交易状态
                if ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)) {
                    // 修改交易记录状态为已支付
                    paymentService.upDatePaymentInfoStatus(outTradeNo, PaymentType.ALIPAY.name(), paramsMap);
                    return "success";
                }
            } catch (Exception e) {
                // 删除ley
                redisTemplate.delete(paramsMap.get("notify_id"));
                e.printStackTrace();
                log.error("异步处理失败{},订单号是", paramsMap.get("out_trade_no"));
            }
        } else {
            // TODO 验签失败则记录异常日志，并在response中返回failure.
            return "failure";
        }
        return "failure";
    }

    /**
     * 发起退款
     * @param orderId
     * @return
     */
    @GetMapping("refund/{orderId}")
    public Result refund(@PathVariable Long orderId){
        //  调用服务层方法 81 -- true; 只要返回true、就表示退款成功！
        Boolean flag = this.alipayService.refund(orderId);
        return flag.equals(true)?Result.ok(flag):Result.fail(false).message("退款失败");
    }

    /**
     * 关闭支付宝交易记录
     * @param orderId
     * @return
     */
    @GetMapping("closeAlipay/{orderId}")
    public Result closeAlipay(@PathVariable Long orderId){
        //  调用服务层方法 81 -- true; 只要返回true、就表示退款成功！
        Boolean flag = this.alipayService.closeAlipay(orderId);
        return flag.equals(true)?Result.ok(flag):Result.fail(false).message("关闭失败");
    }

    /**
     * 查看是否有交易记录
     * @param orderId
     * @return
     */
    @GetMapping("checkPayment/{orderId}")
    public Result checkPayment(@PathVariable Long orderId){
        //  调用服务层方法
        Boolean flag = this.alipayService.checkPayment(orderId);
        return flag.equals(true)?Result.ok(flag):Result.fail(false).message("没有交易记录");
    }

    /**
     * 查看是否有本地交易记录
     * @param outTradeNo
     * @return
     */
    @GetMapping("/getPaymentInfo/{outTradeNo}")
    public PaymentInfo getPaymentInfo(@PathVariable String outTradeNo){
        //  调用服务层方法
        return this.paymentService.getPaymentInfo(outTradeNo,PaymentType.ALIPAY.name());
    }


}